package org.edgar.example.DB.Oracle;

import org.geotools.filter.visitor.DuplicatingFilterVisitor;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.io.WKTReader;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.spatial.*;
import org.opengis.filter.*;
import org.opengis.filter.temporal.*;
import org.opengis.geometry.BoundingBox;
import org.geotools.geometry.jts.JTS;

/**
 *
 */
public class GeometryExtractor implements FilterVisitor {

    private Geometry extractedGeometry;

    public Geometry getExtractedGeometry() {
        return extractedGeometry;
    }

    private Geometry extractFromExpression(Expression expr) {
        Object result = expr.evaluate(null);
        if (result instanceof Geometry) {
            return (Geometry) result;
        }
        if (result instanceof BoundingBox) {
            return JTS.toGeometry((BoundingBox) result);
        }
        if (result instanceof Envelope) {
            return JTS.toGeometry((Envelope) result);
        }
        if (result instanceof String) {
            try {
                return new WKTReader().read((String) result);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public Object visit(BBOX filter, Object data) {
        extractedGeometry = JTS.toGeometry(filter.getBounds());
        return extractedGeometry;
    }

    @Override
    public Object visit(Beyond beyond, Object o) {
        return null;
    }

    @Override
    public Object visit(Contains filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Crosses filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Disjoint filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(DWithin filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Equals filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Intersects filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Overlaps filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Touches filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    @Override
    public Object visit(Within filter, Object data) {
        extractedGeometry = extractFromExpression(filter.getExpression2());
        return extractedGeometry;
    }

    // Temporal filters – typically no geometry
    @Override public Object visit(After filter, Object data) { return null; }
    @Override public Object visit(AnyInteracts filter, Object data) { return null; }
    @Override public Object visit(Before filter, Object data) { return null; }
    @Override public Object visit(Begins filter, Object data) { return null; }
    @Override public Object visit(BegunBy filter, Object data) { return null; }
    @Override public Object visit(During filter, Object data) { return null; }
    @Override public Object visit(EndedBy filter, Object data) { return null; }
    @Override public Object visit(Ends filter, Object data) { return null; }
    @Override public Object visit(Meets filter, Object data) { return null; }
    @Override public Object visit(MetBy filter, Object data) { return null; }
    @Override public Object visit(OverlappedBy filter, Object data) { return null; }
    @Override public Object visit(TContains filter, Object data) { return null; }
    @Override public Object visit(TEquals filter, Object data) { return null; }
    @Override public Object visit(TOverlaps filter, Object data) { return null; }

    // Logical filters – recurse into children
    @Override
    public Object visit(And filter, Object data) {
        for (Filter f : filter.getChildren()) {
            f.accept(this, data);
        }
        return extractedGeometry;
    }

    @Override
    public Object visit(Or filter, Object data) {
        for (Filter f : filter.getChildren()) {
            f.accept(this, data);
        }
        return extractedGeometry;
    }

    @Override
    public Object visit(Not filter, Object data) {
        filter.getFilter().accept(this, data);
        return extractedGeometry;
    }

    // Property filters – usually not geometry
    @Override public Object visit(Id filter, Object data) { return null; }
    @Override public Object visit(PropertyIsBetween filter, Object data) { return null; }
    @Override public Object visit(PropertyIsEqualTo filter, Object data) { return null; }
    @Override public Object visit(PropertyIsNotEqualTo filter, Object data) { return null; }
    @Override public Object visit(PropertyIsGreaterThan filter, Object data) { return null; }
    @Override public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object data) { return null; }
    @Override public Object visit(PropertyIsLessThan filter, Object data) { return null; }
    @Override public Object visit(PropertyIsLessThanOrEqualTo filter, Object data) { return null; }
    @Override public Object visit(PropertyIsLike filter, Object data) { return null; }
    @Override public Object visit(PropertyIsNull filter, Object data) { return null; }
    @Override public Object visit(PropertyIsNil filter, Object data) { return null; }

    // Include/Exclude/Null
    @Override public Object visit(IncludeFilter filter, Object data) { return null; }
    @Override public Object visit(ExcludeFilter filter, Object data) { return null; }
    @Override public Object visitNullFilter(Object data) { return null; }

    @Override
    public Object visit(NativeFilter filter, Object data) {
        return null;
    }
}
